if (!String.prototype.format) {
    String.prototype.format = function() {
        var args = arguments;
        return this.replace(/{(\d+)}/g, function(match, number) {
            return typeof args[number] != 'undefined' ? args[number] : match;
        });
    };
}

if (!Date.prototype.format) {
    Date.prototype.format = function (fmt) {
        var o = {
            "M+": this.getMonth() + 1,
            "d+": this.getDate(),
            "h+": this.getHours(),
            "m+": this.getMinutes(),
            "s+": this.getSeconds(),
            "q+": Math.floor((this.getMonth() + 3) / 3),
            "S": this.getMilliseconds()
        };
        if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
        for (var k in o)
            if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
        return fmt;
    };
}

function isNull(str) {
    return str == null || str.value == "";
}

var WConfig = {
    ajax: {
        timeout: 500000,        // 超时
        loginStatus: 80403,     // 需要登录
        loginUrl: '/index.html' // 登录地址
    }
};

var WFail = {
    failHttp: function(data, textStatus, jqXHR, callback, defaultReturn) {
        if (callback && $.isFunction(callback)) {
            if (defaultReturn) {
                callback({
                    data: defaultReturn,
                    status: jqXHR.status,
                    message: jqXHR.statusText
                });
                return;
            }
            callback({
                data: null,
                status: jqXHR.status,
                message: jqXHR.statusText
            });
        }

    },
    failApi: function(data, textStatus, jqXHR, callback, defaultReturn) {
        switch (data.status) {
            case WConfig.ajax.loginStatus:
                location.href = WConfig.ajax.loginUrl;
                break;
        }
        if (callback && $.isFunction(callback)) {
            if (defaultReturn) {
                callback({
                    data: defaultReturn,
                    status: data.status,
                    message: data.message
                });
                return;
            }
            callback({
                data: null,
                status: data.status,
                message: data.message
            });
        }
    },
    failTimeOut: function(data, textStatus, jqXHR, callback, defaultReturn) {
        if (callback && $.isFunction(callback)) {
            if (defaultReturn) {
                callback({
                    data: defaultReturn,
                    status: jqXHR.status,
                    message: jqXHR.statusText
                });
                return;
            }
            callback({
                data: null,
                status: jqXHR.status,
                message: jqXHR.statusText
            });
        }
    },
};

function WAjaxCall(ajaxOptions, callback, defaultReturn) {
    $.ajax(ajaxOptions)
    .done(function(data, textStatus, jqXHR) {
        if (callback && $.isFunction(callback)) {
            if (data.status == 200) {
                // status: 200
                callback(data);
            } else {
                WFail.failApi(data, textStatus, jqXHR, callback, defaultReturn);
            }
        }
    })
    .fail(function( jqXHR, textStatus, errorThrown) {
        if (textStatus == 'timeout') {
            // 超时处理
            WFail.failTimeOut(null, textStatus, jqXHR, callback, defaultReturn);
            return;
        }
        WFail.failHttp(null, textStatus, jqXHR, callback, defaultReturn);
    });
}

function WJsonCall(url, parameter, callback, defaultReturn) {
    var ajaxOptions = {
        type: "POST",
        url: url,
        data: $.toJSON(parameter),
        dataType: "json",
        contentType : 'application/json;charset=utf-8',
        timeout: WConfig.ajax.timeout
    };
    WAjaxCall(ajaxOptions, callback, defaultReturn);
}

function WDeleteJsonCall(url, parameter, callback, defaultReturn) {
    var ajaxOptions = {
        type: "DELETE",
        url: url,
        data: $.toJSON(parameter),
        dataType: "json",
        contentType : 'application/json;charset=utf-8',
        timeout: WConfig.ajax.timeout
    };
    WAjaxCall(ajaxOptions, callback, defaultReturn);
}

function WPutJsonCall(url, parameter, callback, defaultReturn) {
    var ajaxOptions = {
        type: "PUT",
        url: url,
        data: $.toJSON(parameter),
        dataType: "json",
        contentType : 'application/json;charset=utf-8',
        timeout: WConfig.ajax.timeout
    };
    WAjaxCall(ajaxOptions, callback, defaultReturn);
}

function WPostJsonCall(url, parameter, callback, defaultReturn) {
    WJsonCall(url, parameter, callback, defaultReturn);
}

function WBodyCall(url, parameter, callback, defaultReturn) {
    WJsonCall(url, parameter, callback, defaultReturn);
}

function WPostCall(url, parameter, callback, defaultReturn) {
    var ajaxOptions = {
        type: "POST",
        url: url,
        data: parameter,
        timeout: WConfig.ajax.timeout
    };
    WAjaxCall(ajaxOptions, callback, defaultReturn);
}

function WGetCall(url, parameter, callback, defaultReturn) {
    var ajaxOptions = {
        type: "GET",
        url: url,
        data: parameter,
        timeout: WConfig.ajax.timeout
    };
    WAjaxCall(ajaxOptions, callback, defaultReturn);
}

// 获取对象中多个层级的值
// param dataObject object/array 数据对象，数组、对象或复杂结构对象
// param depthKey string 访问路径
// param defaultValue 默认值
// return 指定路径的值，或者默认值
function depthValue(dataObject, depthKey, defaultValue) {
    var _depthKey = null;
    if (typeof depthKey == 'string') {
        _depthKey = depthKey.split('.');
    } else {
        _depthKey = depthKey;
    }
    var current = dataObject;
    var keyCount = _depthKey.length;
    for (var i = 0; i < keyCount; i++) {
        if (typeof current != 'object') {
            break;
        }
        var key = _depthKey.shift();
        current = current[key];
        if (current == undefined) {
            return defaultValue == undefined ? null : defaultValue;
        }
    }
    return current;
}



/**
 * 获得指定表单里的所有值
 * @param $form
 */
function formValue(formJqObj, isFaultTolerant, isArray) {
    var eles = formJqObj[0].elements;
    var data = {};
    // 字段
    $.each(eles, function(i, element) {
        var target = $(element);
        var name = target.attr('name');
        if (!name) {
            if (isFaultTolerant === true) {
                var id = target.attr('id');
                if (id)
                    name = id;
                else
                    return;
            } else {
                return;
            }
        }
        var tag = element.tagName.toLowerCase();
        if (['select', 'textarea'].indexOf(tag) > -1) {
            data[name] = null;
            return;
        }
        var type = target.attr('type').toLowerCase();
        if (['radio', 'checkbox', 'text', 'password', 'hidden'].indexOf(type) > -1) {
            data[name] = null;
            return;
        }
    });

    // 取值
    $.each(eles, function(i, element) {
        var target = $(element);
        var name = target.attr('name');
        if (!name) {
            if (isFaultTolerant === true) {
                var id = target.attr('id');
                if (id)
                    name = id;
                else
                    return;
            } else {
                return;
            }
        }

        // 标签名
        var tag = element.tagName.toLowerCase();
        if (['select', 'textarea'].indexOf(tag) > -1) {
            if (isArray === true) {
                if (!data[name]) {
                    data[name] = [target.val()];
                } else {
                    data[name].push(target.val());
                }
            } else {
                data[name] = target.val();
            }
            return;
        }

        // 标签类型
        var type = target.attr('type').toLowerCase();
        if (type === 'radio') {
            if(element.checked){
                if (isArray === true) {
                    if (!data[name]) {
                        data[name] = [target.val()];
                    } else {
                        data[name].push(target.val());
                    }
                } else {
                    data[name] = target.val();
                }
            }
            return;
        }
        if (type === 'checkbox') {
            if (element.checked && target.attr('data-multi') === 'true') {
                var d = data[name];
                if (!d) {
                    d = data[name] = []
                }
                d.push(target.val());
            } else if (element.checked) {
                if (isArray === true) {
                    if (!data[name]) {
                        data[name] = [target.val()];
                    } else {
                        data[name].push(target.val());
                    }
                } else {
                    data[name] = target.val();
                }
            }
            return;
        }
        if (['text', 'password', 'hidden'].indexOf(type) > -1) {
            if (isArray === true) {
                if (!data[name]) {
                    data[name] = [target.val()];
                } else {
                    data[name].push(target.val());
                }
            } else {
                data[name] = target.val();
            }
            return;
        }
    });
    return data;
}
function formValueById(formId, isFaultTolerant) {
    return formValue($('#' + formId), isFaultTolerant);
}

// 链条工具类
function Chain(){
    var self = this;
    self.index = 0;
    self.chain = [];
    self.reset = function(){
        self.index = 0;
    };
    self.clear = function(){
        self.chain = [];
        self.index = 0;
    };
    self.method = function(fn){
        self.chain.push(fn);
    };
    self.start = function(){
        if(self.chain.length == 0){
            return;
        }
        var next = function(data){
            var fn = self.chain[++self.index];
            if(fn){
                fn(next, data);
            }
        };
        self.chain[0](next);
    };
    return self;
}

// 并行工具类
function AsyncQueue() {
    var self = this;
    self.queue = [];
    self.countdown = 0;
    self._finish = function() {};
    self.reset = function(){
        self.countdown = 0;
    };
    self.action = function(fn){
        self.queue.push(fn);
    };
    self.finish = function(fn){
        self._finish = fn;
    };
    self.start = function(){
        if(self.queue.length == 0){
            return;
        }
        var finish = function(){
            if (++ self.countdown == self.queue.length) {
                self._finish();
            }
        };
        for (var i in self.queue) {
            self.queue[i](finish);
        }
    };
}

var WStorage = {
    setItem: function(key, valueObject) {
        var type = $.type(valueObject);
        switch (type) {
            case 'object':
            case 'array':
                localStorage.setItem('_type_' + key, type);
                localStorage.setItem(key, $.toJSON(valueObject));
                break;
            default:
                localStorage.setItem('_type_' + key, type);
                localStorage.setItem(key, valueObject);
        }
    },
    getItem: function(key) {
        var type = localStorage.getItem('_type_' + key);
        var valueObject = localStorage.getItem(key);
        switch (type) {
            case 'object':
            case 'array':
                valueObject = $.parseJSON(valueObject);
            default:
                return valueObject;
        }
    },
    removeItem: function(key) {
        localStorage.removeItem('_type_' + key);
        localStorage.removeItem(key)
    },
    clear: function(key) {
        localStorage.clear();
    }
};



//==========================================================
//HashCode BEGIN
//==========================================================

/**
 * 将js页面的number类型转换为java的int类型
 * @param num
 * @return intValue
 */
function javaIntValue(num) {
    var MAX_VALUE = 0x7fffffff;
    var MIN_VALUE = -0x80000000;
    if (num > MAX_VALUE || num < MIN_VALUE) {
        return num &= 0xFFFFFFFF;
    }
    return num;
}

/**
 * java String hashCode 的实现
 * @param strKey
 * @return javaIntValue
 */
function javaHashCode(strKey) {
    var hash = 0;
    if (!isNull(strKey)) {
        for (var i = 0; i < strKey.length; i++) {
            hash = hash * 31 + strKey.charCodeAt(i);
            hash = javaIntValue(hash);
        }
    }
    return hash;
}
//==========================================================
//HashCode END
//==========================================================


//// 8 character ID (base=2)
//uuid(8, 2)  //  "01001010"
//// 8 character ID (base=10)
//uuid(8, 10) // "47473046"
//// 8 character ID (base=16)
//uuid(8, 16) // "098F4D35"
function uuid(len, radix) {
    var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
    var uuid = [],
        i;
    radix = radix || chars.length;
    if (len) {
        // Compact form
        for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix];
    } else {
        // rfc4122, version 4 form
        var r;
        // rfc4122 requires these characters
        uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
        uuid[14] = '4';
        // Fill in random data.  At i==19 set the high bits of clock sequence as
        // per rfc4122, sec. 4.1.5
        for (i = 0; i < 36; i++) {
            if (!uuid[i]) {
                r = 0 | Math.random() * 16;
                uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
            }
        }
    }
    return uuid.join('');
}

function CreateID(prefix){
    if(!prefix) prefix = 'ID';
    return '{0}_{1}_{2}'.format(prefix, uuid(8, 16), Math.round( Math.random() * 100 ));
}